﻿using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using RabbitMQ_Service.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace RabbitMQ_Service.Services
{
    public delegate void ReviceMsgDelegate<T>(T value);
 
    public class RabbitMQReviceMsg
    {
        public RabbitMQReceiveConfig config { get; set; }
        public static IConnection conn;
        public RabbitMQReviceMsg(RabbitMQReceiveConfig _config)
        {
            this.config = _config;
        }
        public IConnection GetConnection()
        {
            if (conn==null)
            {
                conn = RabbitMQBaseService.GetConnection(this.config.IP, this.config.Port, this.config.UserName, this.config.UserPwd, this.config.VirtualHost, 60);
            }
            return conn;
        }
        public void Revice<T>(ReviceMsgDelegate<T> reviceMethond)
        {
            try
            {
                using (var channel=this.GetConnection().CreateModel())
                {
                    if (!string.IsNullOrWhiteSpace(this.config.ExchangeName))
                    {
                        channel.ExchangeDeclare(this.config.ExchangeName, this.config.ExchangeType.ToString(), this.config.DurableQueue);
                        channel.QueueDeclare(this.config.QueueName, this.config.DurableQueue, false, false, null);
                        channel.QueueBind(this.config.QueueName, this.config.ExchangeName, this.config.RoutingKey);
                    }
                    else
                    {
                        channel.QueueDeclare(this.config.QueueName,this.config.DurableQueue,false,false,null);
                    }
                    //如果接受一个消息但是没有应答，客户端不会接受下一个消息
                    channel.BasicQos(0,1,false);
                    //定义一个消费者在队列上
                    var consumer = new QueueingBasicConsumer(channel);
                    //消费队列  设置应答模式为程序主动应答
                    channel.BasicConsume(this.config.QueueName, false, consumer);
                    while (true)
                    {
                        MsgResultEnum mResult = MsgResultEnum.Retry;
                        ulong delivertTag = 0;
                        try
                        {
                            Thread.Sleep(500);
                            var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
                            delivertTag = ea.DeliveryTag;
                            byte[] data = ea.Body;
                            string str = Encoding.UTF8.GetString(data);
                            T v = JsonConvert.DeserializeObject<T>(str);
                            reviceMethond(v);
                            //消息完成
                            mResult = MsgResultEnum.Accept;

                        }
                        catch (Exception ex)
                        {
                            mResult = MsgResultEnum.Reject;
                        }
                        finally
                        {
                            switch (mResult)
                            {
                                case MsgResultEnum.Accept:
                                    //回复确认处理成功
                                    channel.BasicAck(delivertTag, false);
                                    break;
                                case MsgResultEnum.Reject:
                                    //严重错误  写日志
                                    channel.BasicNack(delivertTag, false, false);

                                    break;
                           
                                case MsgResultEnum.Retry:
                                    channel.BasicNack(delivertTag, false, true);
                                    break;
                            }
                        }

                   }
                }
            }
            catch (Exception)
            {

                throw;
            }
        }
    }
}
